package edu.northwestern.cbits.purple_robot_manager.activities;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.text.format.Formatter;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.GoogleApiAvailability;
import edu.northwestern.cbits.purple_robot_manager.EncryptionManager;
import edu.northwestern.cbits.purple_robot_manager.PurpleRobotApplication;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.config.SchemeConfigFile;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityCheck;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityManager;
import edu.northwestern.cbits.purple_robot_manager.plugins.DataUploadPlugin;
import edu.northwestern.cbits.purple_robot_manager.plugins.HttpUploadPlugin;
import edu.northwestern.cbits.purple_robot_manager.plugins.OutputPlugin;
import edu.northwestern.cbits.purple_robot_manager.plugins.OutputPluginManager;
import edu.northwestern.cbits.purple_robot_manager.triggers.Trigger;
import edu.northwestern.cbits.purple_robot_manager.triggers.TriggerManager;
@SuppressLint("SimpleDateFormat")
public class DiagnosticActivity extends AppCompatActivity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.getSupportActionBar().setTitle(R.string.activity_diagnostic_title);
this.setContentView(R.layout.layout_diagnostic_activity);
}
@SuppressWarnings("deprecation")
protected void onResume()
{
super.onResume();
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
TextView userId = (TextView) this.findViewById(R.id.user_id_value);
TextView probeStatus = (TextView) this.findViewById(R.id.probe_status_value);
TextView uploadStatus = (TextView) this.findViewById(R.id.upload_status_value);
TextView lastUpload = (TextView) this.findViewById(R.id.last_upload_value);
TextView prVersion = (TextView) this.findViewById(R.id.pr_version_value);
TextView gpsVersion = (TextView) this.findViewById(R.id.play_services_version_value);
TextView permissionsStatus = (TextView) this.findViewById(R.id.pr_permissions_value);
userId.setText("\"" + EncryptionManager.getInstance().getUserId(this) + "\"");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean probeEnabled = prefs.getBoolean("config_probes_enabled", false);
if (probeEnabled)
probeStatus.setText(R.string.probe_status_enabled);
else
probeStatus.setText(R.string.probe_status_disabled);
PurpleRobotApplication.fixPreferences(this, true);
boolean uploadEnabled = DataUploadPlugin.uploadEnabled(this);
if (uploadEnabled)
{
boolean wifiOnly = DataUploadPlugin.restrictToWifi(prefs);
boolean powerOnly = DataUploadPlugin.restrictToCharging(prefs);
if (wifiOnly && powerOnly)
uploadStatus.setText(R.string.upload_status_enabled_wifi_charging_only);
else if (wifiOnly)
uploadStatus.setText(R.string.upload_status_enabled_wifi_only);
else if (powerOnly)
uploadStatus.setText(R.string.upload_status_enabled_charging_only);
else
uploadStatus.setText(R.string.upload_status_enabled);
}
else
uploadStatus.setText(R.string.upload_status_disabled);
long lastUploadTime = DataUploadPlugin.lastUploadTime(prefs);
long lastPayloadSize = DataUploadPlugin.lastUploadSize(prefs) / 1024;
if (lastUploadTime != -1 && lastPayloadSize != -1)
{
SimpleDateFormat sdf = new SimpleDateFormat("MMM d - HH:mm:ss");
String dateString = sdf.format(new Date(lastUploadTime));
lastUpload.setText(String.format(this.getString(R.string.last_upload_format), dateString, lastPayloadSize));
}
TextView uploadCount = (TextView) this.findViewById(R.id.pending_files_value);
uploadCount.setText(this.getString(R.string.pending_files_file, DataUploadPlugin.pendingFileCount(this)));
if (prefs.getBoolean("config_enable_log_server", false))
{
TextView pendingEventsCount = (TextView) this.findViewById(R.id.pending_log_events_value);
pendingEventsCount.setText(this.getString(R.string.pending_log_events_value, LogManager.getInstance(this).pendingEventsCount()));
}
try
{
PackageInfo pInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
prVersion.setText(pInfo.versionName);
}
catch (NameNotFoundException e)
{
LogManager.getInstance(this).logException(e);
}
gpsVersion.setText("" + GoogleApiAvailability.GOOGLE_PLAY_SERVICES_VERSION_CODE);
TextView okText = (TextView) this.findViewById(R.id.pr_error_none_value);
LinearLayout errorList = (LinearLayout) this.findViewById(R.id.pr_error_list);
errorList.removeAllViews();
final SanityManager sanity = SanityManager.getInstance(this);
if (sanity.getErrorLevel() != SanityCheck.OK)
{
errorList.setVisibility(View.VISIBLE);
okText.setVisibility(View.GONE);
Map<String, String> errors = sanity.errors();
if (errors.size() > 0)
{
errorList.setVisibility(View.VISIBLE);
for (String error : errors.keySet())
{
TextView errorLine = new TextView(this);
errorLine.setText(errors.get(error));
errorLine.setTextColor(0xffff4444);
errorLine.setTextSize(18);
LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
layout.setMargins(0, 0, 0, 10);
errorLine.setLayoutParams(layout);
final String errorKey = error;
errorLine.setOnClickListener(new OnClickListener()
{
public void onClick(View view)
{
sanity.runActionForAlert(errorKey);
}
});
errorList.addView(errorLine);
}
}
Map<String, String> warnings = sanity.warnings();
if (warnings.size() > 0)
{
for (String error : warnings.keySet())
{
TextView errorLine = new TextView(this);
errorLine.setText(warnings.get(error));
errorLine.setTextColor(0xffffbb33);
errorLine.setTextSize(18);
LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
layout.setMargins(0, 0, 0, 10);
errorLine.setLayoutParams(layout);
final String errorKey = error;
errorLine.setOnClickListener(new OnClickListener()
{
public void onClick(View view)
{
sanity.runActionForAlert(errorKey);
}
});
errorList.addView(errorLine);
}
}
}
else
{
errorList.setVisibility(View.GONE);
okText.setVisibility(View.VISIBLE);
}
TextView triggerList = (TextView) this.findViewById(R.id.installed_triggers_value);
StringBuilder triggerSb = new StringBuilder();
List<Trigger> triggers = TriggerManager.getInstance(this).allTriggers();
if (triggers.size() > 0)
{
for (Trigger trigger : triggers)
{
if (triggerSb.length() > 0)
triggerSb.append("\n");
triggerSb.append(trigger.getDiagnosticString(this));
}
triggerList.setText(triggerSb.toString());
}
else
triggerList.setText(R.string.no_installed_triggers_label);
TextView sensorsList = (TextView) this.findViewById(R.id.available_sensors_value);
StringBuilder sb = new StringBuilder();
SensorManager sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
for (Sensor s : sensorManager.getSensorList(Sensor.TYPE_ALL))
{
if (sb.length() > 0)
sb.append("\n");
sb.append(s.getName());
}
sensorsList.setText(sb.toString());
String ipAddress = null;
WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo != null)
{
int ip = wifiInfo.getIpAddress();
ipAddress = Formatter.formatIpAddress(ip);
}
else
{
try
{
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface iface = null;
while (ifaces.hasMoreElements() && (iface = ifaces.nextElement()) != null && ipAddress == null)
{
if (!iface.getName().equals("lo"))
{
Enumeration<InetAddress> ips = iface.getInetAddresses();
InetAddress ipAddr = null;
while (ips.hasMoreElements() && (ipAddr = ips.nextElement()) != null)
{
ipAddress = ipAddr.getHostAddress();
}
}
}
}
catch (SocketException e)
{
LogManager.getInstance(this).logException(e);
}
}
if (ipAddress != null)
{
TextView ipAddressView = (TextView) this.findViewById(R.id.ip_address_value);
ipAddressView.setText(ipAddress);
}
final DiagnosticActivity me = this;
permissionsStatus.setText(PermissionsActivity.status(this));
switch(PermissionsActivity.statusCode(this))
{
case REQUIRED_MISSING:
permissionsStatus.setTextColor(0xffff4444);
break;
case OPTIONAL_MISSING:
permissionsStatus.setTextColor(0xffffbb33);
break;
}
permissionsStatus.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view)
{
Intent intent = new Intent(me, PermissionsActivity.class);
me.startActivity(intent);
}
});
}
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.menu_diagnostics, menu);
return true;
}
public void onBackPressed()
{
if (this.isTaskRoot())
{
Intent intent = new Intent(this, StartActivity.class);
this.startActivity(intent);
}
this.finish();
}
public boolean onOptionsItemSelected(MenuItem item)
{
final int itemId = item.getItemId();
if (itemId == android.R.id.home)
{
this.onBackPressed();
}
if (itemId == R.id.menu_email_item)
{
StringBuilder message = new StringBuilder();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String newline = System.getProperty("line.separator");
message.append(this.getString(R.string.user_id_label));
message.append(newline);
message.append("\"" + EncryptionManager.getInstance().getUserId(this) + "\"");
message.append(newline);
message.append(newline);
message.append(this.getString(R.string.probe_status_label));
message.append(newline);
boolean probeEnabled = prefs.getBoolean("config_probes_enabled", false);
if (probeEnabled)
message.append(this.getString(R.string.probe_status_enabled));
else
message.append(this.getString(R.string.probe_status_disabled));
message.append(newline);
message.append(newline);
message.append(this.getString(R.string.upload_status_label));
message.append(newline);
PurpleRobotApplication.fixPreferences(this, true);
boolean uploadEnabled = prefs.getBoolean("config_enable_data_server", false);
if (uploadEnabled)
{
boolean wifiOnly = prefs.getBoolean("config_restrict_data_wifi", true);
if (wifiOnly)
message.append(this.getString(R.string.upload_status_enabled_wifi_only));
else
message.append(this.getString(R.string.upload_status_enabled));
}
else
message.append(this.getString(R.string.upload_status_disabled));
message.append(newline);
message.append(newline);
message.append(this.getString(R.string.last_upload_label));
message.append(newline);
if (prefs.contains("http_last_upload") && prefs.contains("http_last_payload_size"))
{
long lastUploadTime = prefs.getLong("http_last_upload", 0);
long lastPayloadSize = prefs.getLong("http_last_payload_size", 0) / 1024;
SimpleDateFormat sdf = new SimpleDateFormat("MMM d - HH:mm:ss");
String dateString = sdf.format(new Date(lastUploadTime));
message.append(String.format(this.getString(R.string.last_upload_format), dateString, lastPayloadSize));
}
else
message.append(this.getString(R.string.last_upload_placeholder));
message.append(newline);
message.append(newline);
OutputPlugin plugin = OutputPluginManager.sharedInstance.pluginForClass(this, HttpUploadPlugin.class);
if (plugin instanceof HttpUploadPlugin)
{
HttpUploadPlugin http = (HttpUploadPlugin) plugin;
message.append(this.getString(R.string.robot_pending_count_label));
message.append(newline);
message.append(this.getString(R.string.pending_files_file, http.pendingFilesCount()));
message.append(newline);
message.append(newline);
}
message.append(this.getString(R.string.pr_errors_label));
message.append(newline);
final SanityManager sanity = SanityManager.getInstance(this);
if (sanity.getErrorLevel() != SanityCheck.OK)
{
Map<String, String> errors = sanity.errors();
if (errors.size() > 0)
{
for (String error : errors.keySet())
{
message.append(errors.get(error));
message.append(newline);
}
message.append(newline);
}
Map<String, String> warnings = sanity.warnings();
if (warnings.size() > 0)
{
for (String error : warnings.keySet())
{
message.append(warnings.get(error));
message.append(newline);
}
message.append(newline);
}
}
else
{
message.append(this.getString(R.string.pr_errors_none_label));
message.append(newline);
}
message.append(newline);
message.append(this.getString(R.string.pr_version_label));
message.append(newline);
try
{
PackageInfo pInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
message.append(pInfo.versionName);
}
catch (NameNotFoundException e)
{
LogManager.getInstance(this).logException(e);
}
message.append(newline);
message.append(newline);
message.append(this.getString(R.string.play_services_version_label));
message.append(newline);
message.append("" + GoogleApiAvailability.GOOGLE_PLAY_SERVICES_VERSION_CODE);
message.append(newline);
message.append(newline);
message.append(this.getString(R.string.available_sensors_label));
message.append(newline);
StringBuilder sb = new StringBuilder();
SensorManager sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
for (Sensor s : sensorManager.getSensorList(Sensor.TYPE_ALL))
{
if (sb.length() > 0)
sb.append("\n");
sb.append(s.getName());
}
message.append(sb.toString());
try
{
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_SUBJECT, this.getString(R.string.email_diagnostic_subject));
intent.putExtra(Intent.EXTRA_TEXT, message.toString());
SchemeConfigFile scheme = new SchemeConfigFile(this);
File cacheDir = this.getExternalCacheDir(); // Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
if (cacheDir.exists() == false)
cacheDir.mkdirs();
File configFile = new File(cacheDir, "config.scm");
FileOutputStream fout = new FileOutputStream(configFile);
fout.write(scheme.toString().getBytes(Charset.defaultCharset().name()));
fout.flush();
fout.close();
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(configFile));
this.startActivity(intent);
}
catch (ActivityNotFoundException e)
{
try
{
Intent mailIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:c-karr@northwestern.edu"));
mailIntent.putExtra(Intent.EXTRA_SUBJECT, this.getString(R.string.email_diagnostic_subject));
mailIntent.putExtra(Intent.EXTRA_TEXT, message.toString());
this.startActivity(mailIntent);
}
catch (ActivityNotFoundException ex)
{
Toast.makeText(this, R.string.toast_mail_not_found, Toast.LENGTH_LONG).show();
}
}
catch (IOException e)
{
LogManager.getInstance(this).logException(e);
}
}
return true;
}
}